package cn.yangliu.nacos.oauth2.config;

import java.util.Collection;
import java.util.Objects;

import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2RefreshToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStoreSerializationStrategy;

/**
 * The interface Jwt redis token store.
 *
 * @author 问道于盲
 * @date 2019 -04-17 装饰器模式 实际干活的是redisTokenStore
 */
public class JwtRedisTokenStore extends JwtTokenStore {

    /**
     * current class instance's member.
     * The Redis token store.
     */
    private RedisTokenStore redisTokenStore;

    /**
     * Instantiates a new Jwt redis token store.
     * allow any class to create a new instance.
     *
     * @param jwtTokenEnhancer       the jwt token enhancer
     * @param redisConnectionFactory the redis connection factory
     */
    public JwtRedisTokenStore(JwtAccessTokenConverter jwtTokenEnhancer,
                               RedisConnectionFactory redisConnectionFactory) {
        this(jwtTokenEnhancer, redisConnectionFactory, null);
    }

    /**
     * Instantiates a new Jwt redis token store.
     * allow any class to create a new instance.
     *
     * @param jwtTokenEnhancer       the jwt token enhancer
     * @param redisConnectionFactory the redis connection factory
     * @param strategy               the strategy
     */
    public JwtRedisTokenStore(JwtAccessTokenConverter jwtTokenEnhancer,
                               RedisConnectionFactory redisConnectionFactory,
                               RedisTokenStoreSerializationStrategy strategy) {
        super(jwtTokenEnhancer);
        redisTokenStore = new RedisTokenStore(redisConnectionFactory);
        if (Objects.nonNull(strategy)) {
            redisTokenStore.setSerializationStrategy(strategy);
        }
    }


    /**
     * Store access token.
     *
     * @param token          the token
     * @param authentication the authentication
     */
    @Override
    public void storeAccessToken(OAuth2AccessToken token, OAuth2Authentication authentication) {
        redisTokenStore.storeAccessToken(token, authentication);
    }


    /**
     * Store refresh token.
     *
     * @param refreshToken   the refresh token
     * @param authentication the authentication
     */
    @Override
    public void storeRefreshToken(OAuth2RefreshToken refreshToken, OAuth2Authentication authentication) {
        redisTokenStore.storeRefreshToken(refreshToken, authentication);
    }

    /**
     * Read authentication o auth 2 authentication.
     *
     * @param token the token
     * @return the o auth 2 authentication
     */
    @Override
    public OAuth2Authentication readAuthentication(OAuth2AccessToken token) {
//                redisTemplate
        return redisTokenStore.readAuthentication(token);
    }

    /**
     * Read authentication o auth 2 authentication.
     *
     * @param token the token
     * @return the o auth 2 authentication
     */
    @Override
    public OAuth2Authentication readAuthentication(String token) {
        return redisTokenStore.readAuthentication(token);
    }

    /**
     * Read access token o auth 2 access token.
     *
     * @param tokenValue the token value
     * @return the o auth 2 access token
     */
    @Override
    public OAuth2AccessToken readAccessToken(String tokenValue) {
        return redisTokenStore.readAccessToken(tokenValue);
    }

    /**
     * Remove access token.
     *
     * @param token the token
     */
    @Override
    public void removeAccessToken(OAuth2AccessToken token) {
        redisTokenStore.removeAccessToken(token);
    }

    /**
     * Read refresh token o auth 2 refresh token.
     *
     * @param tokenValue the token value
     * @return the o auth 2 refresh token
     */
    @Override
    public OAuth2RefreshToken readRefreshToken(String tokenValue) {
        return redisTokenStore.readRefreshToken(tokenValue);
    }

    /**
     * Read authentication for refresh token o auth 2 authentication.
     *
     * @param token the token
     * @return the o auth 2 authentication
     */
    @Override
    public OAuth2Authentication readAuthenticationForRefreshToken(OAuth2RefreshToken token) {
        return redisTokenStore.readAuthenticationForRefreshToken(token);
    }

    /**
     * Remove refresh token.
     *
     * @param token the token
     */
    @Override
    public void removeRefreshToken(OAuth2RefreshToken token) {
        redisTokenStore.removeRefreshToken(token);
    }

    /**
     * Remove access token using refresh token.
     *
     * @param refreshToken the refresh token
     */
    @Override
    public void removeAccessTokenUsingRefreshToken(OAuth2RefreshToken refreshToken) {
        redisTokenStore.removeAccessTokenUsingRefreshToken(refreshToken);
    }

    /**
     * current class method for getter.
     * Gets access token.
     *
     * @param authentication the authentication
     * @return the access token
     */
    @Override
    public OAuth2AccessToken getAccessToken(OAuth2Authentication authentication) {
        return redisTokenStore.getAccessToken(authentication);
    }

    /**
     * Find tokens by client id and user name collection.
     *
     * @param clientId the client id
     * @param userName the user name
     * @return the collection
     */
    @Override
    public Collection<OAuth2AccessToken> findTokensByClientIdAndUserName(String clientId, String userName) {
        return redisTokenStore.findTokensByClientIdAndUserName(clientId, userName);
    }

    /**
     * Find tokens by client id collection.
     *
     * @param clientId the client id
     * @return the collection
     */
    @Override
    public Collection<OAuth2AccessToken> findTokensByClientId(String clientId) {
        return redisTokenStore.findTokensByClientId(clientId);
    }

}
